package br.unicamp.ic.inf300.arena.persistencia.dao.impl;

import java.sql.Time;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import br.unicamp.ic.inf300.arena.modelo.artistico.Espetaculo;
import br.unicamp.ic.inf300.arena.modelo.financeiro.ContaContabil;
import br.unicamp.ic.inf300.arena.modelo.logistico.Evento;
import br.unicamp.ic.inf300.arena.modelo.logistico.Sala;
import br.unicamp.ic.inf300.arena.modelo.logistico.UnidadeNegocio;
import br.unicamp.ic.inf300.arena.persistencia.dao.IContaContabilDAO;
import br.unicamp.ic.inf300.arena.persistencia.dao.IEspetaculoDAO;
import br.unicamp.ic.inf300.arena.persistencia.dao.IEventoDAO;
import br.unicamp.ic.inf300.arena.persistencia.dao.ISalaDAO;
import br.unicamp.ic.inf300.arena.persistencia.dao.IUnidadeNegocioDAO;
import br.unicamp.ic.inf300.framework.persistencia.DAOFactory;
import br.unicamp.ic.inf300.framework.persistencia.SQLUtil;
import br.unicamp.ic.inf300.framework.util.DataUtil;

public class EventoDAOHsql implements IEventoDAO {

	/**
	 * 
	 */
	public Collection<Evento> obterEventosEmCartaz(Date dataInicio,
			Date dataTermino, boolean buscarSemVaga) throws Exception {

		ArrayList<Evento> eventos = null;
		if (dataInicio != null && dataTermino != null) {

			//
			StringBuffer stbQuery = new StringBuffer();
			stbQuery.append(" SELECT ");
			//cols. 0 a 3
			stbQuery.append("   ev.codevento, ev.data, ev.horariosessao, ev.qtdvagaslivre, ");
			//cols. 4 a 6
			stbQuery.append("   ev.valor, ev.codespetaculo, es.tipo, ");
			//cols. 7 a 11
			stbQuery.append("   ev.codsala, s.tipo, s.codunidade, u.codconta, cc.numcartaocredito, u.endereco ");
			stbQuery.append(" FROM ");
			stbQuery.append(IEventoDAO.TABELA_BD + " ev, " + IEspetaculoDAO.TABELA_BD + " es, " + ISalaDAO.TABELA_BD + " s, ");
			stbQuery.append(IUnidadeNegocioDAO.TABELA_BD + " u, " + IContaContabilDAO.TABELA_BD + " cc ");
			stbQuery.append(" WHERE ");
			stbQuery.append("   ev.codespetaculo = es.codespetaculo AND ");
			stbQuery.append("   ev.codsala = s.codsala  AND ");
			stbQuery.append("   s.codunidade = u.codunidade  AND ");
			stbQuery.append("   u.codconta = cc.codconta  AND ");
			stbQuery.append("   ev.data >= ? AND ");
			stbQuery.append("   ev.data <= ? ");

			//
			int qtdVagasLivre = 0;
			Object[] params   = null;
			if(!buscarSemVaga) {
				stbQuery.append(" AND ev.qtdvagaslivre > ? ");

				params = new Object[3];
				params[0] = DataUtil.formatarData(DataUtil.MYSQL_DATE, dataInicio);
				params[1] = DataUtil.formatarData(DataUtil.MYSQL_DATE, dataTermino);
				params[2] = qtdVagasLivre;
			} else {
				params = new Object[2];
				params[0] = DataUtil.formatarData(DataUtil.MYSQL_DATE, dataInicio);
				params[1] = DataUtil.formatarData(DataUtil.MYSQL_DATE, dataTermino);
			}
			stbQuery.append(" ORDER BY ev.data, ev.horariosessao, ev.qtdvagaslivre ASC ");

			Evento evento = null;
			List<Evento> result = null;
			eventos = new ArrayList<Evento>();

			//selectRecordS
			result = (ArrayList<Evento>) SQLUtil.selectRecords(stbQuery.toString(), params);
			if (result != null && result.size() > 0) {
				int codSala       = 0;
				int codEspetaculo = 0;
				int tipoEspetaculo = 0;
				Sala sala = null;
				Espetaculo espetaculo = null;

				//
				IEspetaculoDAO daoEspetaculo = null;
				daoEspetaculo = (IEspetaculoDAO) DAOFactory.getImpl(IEspetaculoDAO.class);

				ISalaDAO daoSala = null;
				daoSala = (ISalaDAO) DAOFactory.getImpl(ISalaDAO.class);

				// itera sobre o resultado da base populando Evento, inclusive com
				// Espetaculo, Sala, UnidadeNegocio e ContaContabil
				for (Iterator iter = result.iterator(); iter.hasNext();) {
					Object[] record = (Object[]) iter.next();
					//
					if (record != null && record.length > 0) {
						evento = new Evento();
						evento.setCodEvento( ((Long) record[0]).longValue() );
						evento.setData( (java.sql.Date) record[1] );
						evento.setHorarioSessao( (Time) record[2] );
						evento.setQtdVagasLivre( ((Integer) record[3]).intValue() );
						evento.setValor( ((Double) record[4]).doubleValue() );
						//FK - Espetaculo
						codEspetaculo  = ((Integer) record[5]).intValue();
						tipoEspetaculo = ((Integer) record[6]).intValue();

						espetaculo = daoEspetaculo.obterEspetaculo(codEspetaculo,
								tipoEspetaculo);
						evento.setEspetaculo(espetaculo);

						//FK - Sala
						codSala = ((Integer) record[7]).intValue();
						int tipoSala = ((Integer) record[8]).intValue();

						sala = daoSala.obterSala(codSala, tipoSala);
						evento.setSala(sala); //Evento x Sala

						//s.codunidade, u.codconta, cc.numcartaocredito
						int codUnidade = ((Integer) record[9]).intValue();
						int codConta = ((Integer) record[10]).intValue();
						long numCartaoConta = ((Long) record[11]).longValue();
						String endereco = (String) record[12];

						ContaContabil contaContabil = new ContaContabil();
						contaContabil.setCodConta(codConta);
						contaContabil.setNumCartaoCredito(numCartaoConta);

						UnidadeNegocio unidade = new UnidadeNegocio();
						unidade.setCodUnidade(codUnidade);
						unidade.setEndereco(endereco);
						unidade.setContaContabil(contaContabil); //UnidadeNegocio x ContaContabil

						sala.setUnidadeNegocio(unidade); //Sala x UnidadeNegocio

						//
						eventos.add(evento);
					}
				}
			}
		}
		return eventos;
	}

	/**
	 * Atualiza qtdVagasLivres conforme param. qtd do Espetaculo associado a PK codigo
	 * 
	 * @param codigo
	 * @param qtd
	 * 
	 * @return int
	 * 
	 * @throws Exception
	 */
	public int atualizar(long codigo, int qtd) throws Exception {
		int result = 0;
		Object[] params = new Object[2];
		params[0] = qtd;
		params[1] = codigo;

		StringBuffer stbQuery = new StringBuffer();
		stbQuery.append(" UPDATE ");
		stbQuery.append(/*SQLUtil.getDbSchema() + "." +*/ IEventoDAO.TABELA_BD
				+ " SET ");
		stbQuery.append(IEventoDAO.COLUMN_QTD_VAGAS_LIVRES + " = ? ");
		stbQuery.append(" WHERE " + IEventoDAO.COLUMN_CODIGO_PK + " = ? ");
		//
		result = SQLUtil.update(stbQuery.toString(), params);
		return result;
	}

	/**
	 * Recupera um evento a partir de seu codigo e todos os beans do grafo de
	 * associacoes de Evento.
	 */
	public Evento obter(long codigo) throws Exception {
		Evento evento = null;		

		StringBuffer stbQuery = new StringBuffer();
		stbQuery.append(" SELECT ");
		//cols.  0 a 3
		stbQuery.append("   ev.codevento, ev.data, ev.horariosessao, ev.qtdvagaslivre, ");
		//cols.  4 a 6
		stbQuery.append("   ev.valor, ev.codespetaculo, es.tipo, ");
		//cols.  7 a 11
		stbQuery.append("   ev.codsala, s.tipo, s.codunidade, u.codconta, cc.numcartaocredito, u.endereco ");
		stbQuery.append(" FROM ");
		stbQuery.append(IEventoDAO.TABELA_BD + " ev, "
				+ IEspetaculoDAO.TABELA_BD + " es, " + ISalaDAO.TABELA_BD
				+ " s, ");
		stbQuery.append(IUnidadeNegocioDAO.TABELA_BD + " u, "
				+ IContaContabilDAO.TABELA_BD + " cc ");
		stbQuery.append(" WHERE ");
		stbQuery.append("   ev.codespetaculo = es.codespetaculo AND ");
		stbQuery.append("   ev.codsala = s.codsala  AND ");
		stbQuery.append("   s.codunidade = u.codunidade  AND ");
		stbQuery.append("   u.codconta = cc.codconta  AND ");
		stbQuery.append("ev." + IEventoDAO.COLUMN_CODIGO_PK + " = ?");
		stbQuery
				.append(" ORDER BY ev.data, ev.horariosessao, ev.qtdvagaslivre ASC ");

		//selectARecord
		Object[] result = (Object[]) SQLUtil.selectARecord(stbQuery.toString(),
				new Object[] { codigo });

		if ( result != null ) {
			int codSala = 0;
			int codEspetaculo = 0;
			int tipoEspetaculo = 0;
			Sala sala = null;
			Espetaculo espetaculo = null;

			//
			IEspetaculoDAO daoEspetaculo = null;
			daoEspetaculo = (IEspetaculoDAO) DAOFactory
					.getImpl(IEspetaculoDAO.class);

			ISalaDAO daoSala = null;
			daoSala = (ISalaDAO) DAOFactory.getImpl(ISalaDAO.class);

			evento = new Evento();
			evento.setCodEvento( ((Long) result[0]).longValue() );
			evento.setData( (java.sql.Date) result[1] );
			evento.setHorarioSessao( (Time) result[2] );
			evento.setQtdVagasLivre( ((Integer) result[3]).intValue() );
			evento.setValor( ((Double) result[4]).doubleValue() );
			//FK - Espetaculo
			codEspetaculo = ( (Integer) result[5] ).intValue();
			tipoEspetaculo = ( (Integer) result[6] ).intValue();

			espetaculo = daoEspetaculo.obterEspetaculo(codEspetaculo,
					tipoEspetaculo);
			evento.setEspetaculo(espetaculo);

			//FK - Sala
			codSala = ( (Integer) result[7] ).intValue();
			int tipoSala = ( (Integer) result[8] ).intValue();

			sala = daoSala.obterSala(codSala, tipoSala);
			evento.setSala(sala); //Evento x Sala

			//s.codunidade, u.codconta, cc.numcartaocredito
			int codUnidade = ( (Integer) result[9] ).intValue();
			int codConta = ( (Integer) result[10] ).intValue();
			long numCartaoConta = ( (Long) result[11] ).longValue();
			String endereco = (String) result[12];

			ContaContabil contaContabil = new ContaContabil();
			contaContabil.setCodConta(codConta);
			contaContabil.setNumCartaoCredito(numCartaoConta);

			UnidadeNegocio unidade = new UnidadeNegocio();
			unidade.setCodUnidade(codUnidade);
			unidade.setEndereco(endereco);
			unidade.setContaContabil(contaContabil); //UnidadeNegocio x ContaContabil

			sala.setUnidadeNegocio(unidade); //Sala x UnidadeNegocio
		}
		return evento;
	}
}